#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>

#define NUM_THREADS 2

using namespace std;

float mat[1000][1000];

int row = 1000;

typedef struct
{
	int threatId;
}threadParm_t;

pthread_barrier_t barrier1;
pthread_barrier_t barrier2;

long long freq,head,tail;

void *LU_pthread_matrix(void *parm)
{
	threadParm_t *p = (threadParm_t *)parm;
	int id = p->threatId;

	for (int k = 0; k < row; k++)
    {
        for (int j = k + 1 + id;j < row;j += NUM_THREADS)
        {
            mat[k][j] = mat[k][j] / mat[k][k];
        }
        mat[k][k] = 1.0;
		pthread_barrier_wait(&barrier1);
		for (int i = k + 1 + id; i < row; i += NUM_THREADS)
		{
			for (int j = k + 1;j < row;j++)
			{
				mat[i][j] = mat[i][j] - mat[i][k] * mat[k][j];
			}
			mat[i][k] = 0;
		}
		pthread_barrier_wait(&barrier2);
	}
	pthread_exit(0);
}

int main()
{
    srand(time(0));
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < row; j++)
            mat[i][j] = rand();
    }
    QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
    pthread_barrier_init(&barrier1, NULL, NUM_THREADS);
    pthread_barrier_init(&barrier2, NULL, NUM_THREADS);
    pthread_t thread[NUM_THREADS];
	threadParm_t threadParm[NUM_THREADS];
    QueryPerformanceCounter((LARGE_INTEGER *)&head);
	for (int i = 0; i < NUM_THREADS; i++)
    {
		threadParm[i].threatId = i;
		pthread_create(&thread[i], NULL, LU_pthread_matrix, (void *)&threadParm[i]);
	}

	for (int i = 0; i < NUM_THREADS; i++)
	{
		pthread_join(thread[i], 0);
	}
    QueryPerformanceCounter((LARGE_INTEGER *)&tail);
    cout <<(tail-head)*1000.0/freq <<endl;
    return 0;
}
